﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ITAP.Core.Modelling.Primitives;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder.Modelling.Components.Constraints
{
    [Serializable]
    public class ConnectedShprossEndsJoinAndAngleIntervalConstraint : IConstraint
    {
        private AngleInterval allowedAngleInterval;

        public ConnectedShprossEndsJoinAndAngleIntervalConstraint(AngleInterval interval)
        {
            this.allowedAngleInterval = interval.Clone() as AngleInterval;
        }

        #region IConstraint Members

        public bool Check(IComponent component)
        {
            return false;
        }

        public void Fix(IComponent component)
        {
            if (!enabled)
                return;
            if (!(component is StickConnector))
                return;

            StickConnector connector = component as StickConnector;
            foreach (IComponent connectedComponent in component.ConnectedComponents)
            {
                if (connectedComponent is Shpross)
                {
                    StickConnectionType sticked;
                    Shpross shpross = connectedComponent as Shpross;
                    ShprossConnector shprossConnector = connector.Parent.Parent as ShprossConnector;
                    ModelPoint measurePoint = ModelCalculations.GetOffsetPoint(connector.StartPoint, connector.Primitives[0].GetTangent(0).Multiply(100));

                    ModelPoint nearestPoint = shpross.GetNearestPointOnComponent(connector.StartPoint, measurePoint, StickConnectionType.ToNearestBorder, out sticked, ProjectionType.Intersection);
                    if (!shpross.Primitives[0].IsInTolerance(nearestPoint, 0))
                    {
                        ConnectionProvider.Disconnect(shpross, connector);
                        //       shprossConnector.Stub.RemoveInnerComponent(connector);
                        return;
                    }
                    else if(!shpross.IsConnected(connector))
                    {
                        ConnectionProvider.Connect(connector, shpross, EndType.Start);
                    }
                    connector.MoveTo(nearestPoint);
                    connector.Parent.Parent.MoveTo(nearestPoint);
                    Angle angleToRotate = null;
                    Angle angleToRotate2 = null;
                    IWidePrimitive shprossPrimitive = shpross.Primitives[0] as IWidePrimitive;
                    if (sticked == StickConnectionType.ToDownBorder)
                    {
                        double offset = shprossPrimitive.DownBorder.GetPathLengthFromProjectionToStart(nearestPoint);
                        //offset = offset / shprossPrimitive.DownBorder.Length;

                        ModelVector tangent = shprossPrimitive.DownBorder.GetTangent(offset).Rotate(new Angle(Math.PI));
                        Angle angle = ModelCalculations.GetAngleBetweenVectors(tangent, connector.Primitives[0].GetTangent(0), false);
                        angleToRotate = allowedAngleInterval.MiddleAngle - angle;
                        connector.Rotate(angleToRotate.Value);

                        ModelVector tangent2 = shprossConnector.Stub.Primitives[0].GetTangent(0);
                        Angle angle2 = ModelCalculations.GetAngleBetweenVectors(tangent2, connector.Primitives[0].GetTangent(0), false);

                        angleToRotate2 = allowedAngleInterval.MiddleAngle - angle2;
                    }
                    else
                    {
                        double offset = shprossPrimitive.UpBorder.GetPathLengthFromProjectionToStart(nearestPoint);
                        offset = offset / shprossPrimitive.UpBorder.Length;

                        ModelVector tangent = shprossPrimitive.UpBorder.GetTangent(offset);
                        Angle angle = ModelCalculations.GetAngleBetweenVectors(tangent, connector.Primitives[0].GetTangent(0), false);
                        angleToRotate = allowedAngleInterval.MiddleAngle - angle;
                        connector.Rotate(angleToRotate.Value);

                        ModelVector tangent2 = shprossConnector.Stub.Primitives[0].GetTangent(0);                        
                        Angle angle2 = ModelCalculations.GetAngleBetweenVectors(tangent2, connector.Primitives[0].GetTangent(0), false);
                        angleToRotate2 = allowedAngleInterval.MiddleAngle - angle2;
                    }

                    connector.Parent.Parent.Rotate(-angleToRotate2.Value, connector.Position);
                    shpross.Update();
                    shprossConnector.Update();
                    foreach (IComponent innerComponent in shprossConnector.InnerComponents)
                        innerComponent.Update();
                }
            }
        }

        private bool enabled = true;
        public bool Enabled
        {
            get
            {
                return enabled;
            }
            set
            {
                enabled = value;
            }
        }

        public ConstraintAction Action
        {
            get { return ConstraintAction.Fix; }
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
